/****************************************************************************
 *
 *   Copyright (C) 2019-2024 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file blocking_list.hpp
 *
 * A thread-safe blocking intrusive sorted list for FreeRTOS.
 * 
 * This is a C++ wrapper around the C intrusive_sorted_list implementation,
 * providing thread safety using FreeRTOS mutexes and LockGuard.
 */

#pragma once

#include "intrusive_sorted_list.h"
#include "lock_guard.hpp"
#include "FreeRTOS.h"
#include "semphr.h"

#ifdef __cplusplus

/**
 * @class BlockingList
 * @brief Thread-safe wrapper for intrusive_sorted_list_t
 *
 * This class provides thread-safe access to an intrusive sorted list
 * using FreeRTOS mutexes. All operations are automatically protected
 * by mutex locks using RAII-style LockGuard.
 *
 * Usage:
 * @code
 * typedef struct {
 *     intrusive_sorted_list_node_t node;
 *     int value;
 *     char name[32];
 * } MyItem;
 *
 * int compare_items(const void *a, const void *b) {
 *     const MyItem *item_a = (const MyItem *)a;
 *     const MyItem *item_b = (const MyItem *)b;
 *     return strcmp(item_a->name, item_b->name) < 0;
 * }
 *
 * BlockingList my_list;
 * my_list.init(offsetof(MyItem, node), compare_items);
 *
 * MyItem item1 = { .value = 42, .name = "test" };
 * my_list.add(&item1);
 *
 * size_t count = my_list.size();
 * my_list.remove(&item1);
 * @endcode
 */
class BlockingList
{
public:
	/**
	 * @brief Constructor - creates mutex
	 */
	BlockingList()
	{
		_mutex = xSemaphoreCreateMutex();
		configASSERT(_mutex != NULL);
	}

	/**
	 * @brief Destructor - destroys mutex
	 */
	~BlockingList()
	{
		if (_mutex != NULL) {
			vSemaphoreDelete(_mutex);
			_mutex = NULL;
		}
	}

	/**
	 * @brief Initialize the list
	 * @param node_offset Offset of intrusive_sorted_list_node_t in your structure
	 * @param compare Comparison function
	 */
	void init(size_t node_offset, intrusive_sorted_list_compare_fn compare)
	{
		intrusive_sorted_list_init(&_list, node_offset, compare);
	}

	/**
	 * @brief Add an item to the list (thread-safe)
	 * @param item Pointer to item to add
	 */
	void add(void *item)
	{
		LockGuard lock(_mutex);
		intrusive_sorted_list_add(&_list, item);
	}

	/**
	 * @brief Remove an item from the list (thread-safe)
	 * @param item Pointer to item to remove
	 * @return true if item was removed, false if not found
	 */
	bool remove(void *item)
	{
		LockGuard lock(_mutex);
		return intrusive_sorted_list_remove(&_list, item);
	}

	/**
	 * @brief Get the size of the list (thread-safe)
	 * @return Number of items in the list
	 */
	size_t size()
	{
		LockGuard lock(_mutex);
		return intrusive_sorted_list_size(&_list);
	}

	/**
	 * @brief Clear the list (thread-safe)
	 */
	void clear()
	{
		LockGuard lock(_mutex);
		intrusive_sorted_list_clear(&_list);
	}

	/**
	 * @brief Get the mutex handle for external locking
	 * @return FreeRTOS mutex handle
	 */
	SemaphoreHandle_t &mutex() { return _mutex; }

private:
	intrusive_sorted_list_t _list;
	SemaphoreHandle_t _mutex;

	// Non-copyable
	BlockingList(const BlockingList &) = delete;
	BlockingList &operator=(const BlockingList &) = delete;
};

/**
 * @class BlockingListTemplate
 * @brief Template version of BlockingList for type-safe pointer storage
 *
 * This template class provides a type-safe wrapper for storing pointers
 * in a thread-safe sorted list. It uses the intrusive_sorted_list_t
 * implementation underneath.
 */
template<typename T>
class BlockingListTemplate
{
public:
	/**
	 * @brief Constructor - creates mutex and initializes list
	 */
	BlockingListTemplate()
	{
		_mutex = xSemaphoreCreateMutex();
		configASSERT(_mutex != NULL);

		// Initialize list with node offset and compare function
		intrusive_sorted_list_init(&_list, offsetof(ListNode, node), compare_nodes);
	}

	/**
	 * @brief Destructor - destroys mutex
	 */
	~BlockingListTemplate()
	{
		if (_mutex != NULL) {
			vSemaphoreDelete(_mutex);
			_mutex = NULL;
		}
	}

	/**
	 * @brief Add an item to the list (thread-safe)
	 * @param item Pointer to add
	 */
	void add(T item)
	{
		ListNode *node = new ListNode();
		node->data = item;
		LockGuard lock(_mutex);
		intrusive_sorted_list_add(&_list, node);
	}

	/**
	 * @brief Remove an item from the list (thread-safe)
	 * @param item Pointer to remove
	 * @return true if item was removed, false if not found
	 */
	bool remove(T item)
	{
		LockGuard lock(_mutex);

		// Find the node containing this item
		intrusive_sorted_list_node_t *node = _list.head;
		while (node != nullptr) {
			ListNode *list_node = (ListNode *)((char *)node - offsetof(ListNode, node));
			if (list_node->data == item) {
				intrusive_sorted_list_remove(&_list, list_node);
				delete list_node;
				return true;
			}
			node = node->sibling;
		}
		return false;
	}

	/**
	 * @brief Get the size of the list (thread-safe)
	 * @return Number of items in the list
	 */
	size_t size()
	{
		LockGuard lock(_mutex);
		return intrusive_sorted_list_size(&_list);
	}

	/**
	 * @brief Clear the list (thread-safe)
	 */
	void clear()
	{
		LockGuard lock(_mutex);

		// Delete all nodes
		intrusive_sorted_list_node_t *node = _list.head;
		while (node != nullptr) {
			intrusive_sorted_list_node_t *next = node->sibling;
			ListNode *list_node = (ListNode *)((char *)node - offsetof(ListNode, node));
			delete list_node;
			node = next;
		}

		intrusive_sorted_list_clear(&_list);
	}

	/**
	 * @brief Get the mutex handle for external locking
	 * @return FreeRTOS mutex handle
	 */
	SemaphoreHandle_t &mutex() { return _mutex; }

	/**
	 * @brief Iterator class for range-based for loops
	 */
	class Iterator
	{
	public:
		Iterator(intrusive_sorted_list_node_t *node) : _node(node) {}

		T operator*() const
		{
			if (_node == nullptr) return nullptr;
			ListNode *list_node = (ListNode *)((char *)_node - offsetof(ListNode, node));
			return list_node->data;
		}

		Iterator &operator++()
		{
			if (_node != nullptr) {
				_node = _node->sibling;
			}
			return *this;
		}

		bool operator!=(const Iterator &other) const
		{
			return _node != other._node;
		}

	private:
		intrusive_sorted_list_node_t *_node;
	};

	/**
	 * @brief Begin iterator (for range-based for loops)
	 * NOTE: Caller must hold the mutex!
	 */
	Iterator begin() { return Iterator(_list.head); }

	/**
	 * @brief End iterator (for range-based for loops)
	 * NOTE: Caller must hold the mutex!
	 */
	Iterator end() { return Iterator(nullptr); }

private:
	struct ListNode {
		intrusive_sorted_list_node_t node;
		T data;
	};

	intrusive_sorted_list_t _list;
	SemaphoreHandle_t _mutex;

	// Comparison function for nodes
	static bool compare_nodes(const void *a, const void *b)
	{
		const ListNode *node_a = (const ListNode *)a;
		const ListNode *node_b = (const ListNode *)b;
		// Compare pointers directly (no specific ordering needed)
		return node_a->data < node_b->data;
	}

	// Non-copyable
	BlockingListTemplate(const BlockingListTemplate &) = delete;
	BlockingListTemplate &operator=(const BlockingListTemplate &) = delete;
};

#endif // __cplusplus

